import javax.swing.RepaintManager;


public class Game
{
	/** The squares of the board */
	private Square board[][];
	/** The name of the player using this GUI */
	private String myName;
	/** The mark used by this player ('X' or 'O') */
	private char myMark;
	/** The mark used by the other player */
	private char otherMark;
	/** A reference to the ui */
	private TicTacToeGui gui;
	/** who's turn is it? */
	private boolean turn;
	
	/** A string spesifying if it's the server or the client */
	private boolean isServer;
	
	NetworkInterface networkInterface;	
	
	public String getName(){
		return myName;
	}
	
	public boolean isServer() {
		return isServer;
	}
	
	public void setMyMark(char mark) {
		this.myMark = mark;
	}
	
	public void setOtherMark(char mark) {
		this.otherMark = mark;
	}
	
	public char getOtherMark() {
		return this.otherMark;
	}
	
	public char getMyMark(){
		return myMark;
	}
	
	public void setTurn(){
		turn = true;
	}
	
	public Square getSquare(int row, int col) {
		return board[row][col];
	}
	
	public Game(){
		
		board = new Square[Constants.BOARD_SIZE][Constants.BOARD_SIZE];
		for(int row = 0; row < board.length; row++){
			for(int col = 0; col < board[row].length; col++) {
				board[row][col] = new Square(this, row, col);
			}
		}

		this.gui = new TicTacToeGui(this);
	}
	
	/**
	 * Marks the specified square of the board with the specified mark.
	 * @param row		The row of the square to mark.
	 * @param column	The column of the square to mark.
	 * @param mark		The mark to use.
	 */
	public void placeMark(int row, int column) {
		if(turn) {
			board[row][column].setMark(myMark);	
			gui.addText("Waiting for the other player to move\n");
		}
		else {
			board[row][column].setMark(otherMark);	
			gui.addText("It's your turn to move! \n");
		}
		update();
	}
	
	/**
	 * Removes all marks from the board.
	 */
	public void clearBoard() {
		for(int row = 0; row < board.length; row++)
			for(int col = 0; col < board[row].length; col++)
				board[row][col].setMark(' ');
		update();
	}
	
	/**
	 * Called by the Square class when an empty square is clicked.
	 * @param row		The row of the square that was clicked.
	 * @param column	The column of the square that was clicked.
	 */
	public void squareClicked(int row, int column) {
		doMove(row, column, getMyMark());
	}
	
	public void doMove(int row, int column, char myMark)
	{
		if(turn) {
			if(board[row][column].getMark() == ' '){
				placeMark(row, column);

				networkInterface.doMove(row, column);
			}
		}
	}

	public void startNewGame(String name) {
		myMark = 'O';
		otherMark = 'X';
		turn = false;
		myName = name;
		this.isServer = true;
		
		gui.addText("A new game has been started. Waiting for a player to join!\n");
		
		
		Server server = new Server(Constants.SERVER_PORT, this);
		networkInterface = server;
	}
	
	public void joinOtherGame(String address, int port) {
		turn = true;
		myMark = 'X';
		otherMark = 'O';
		this.isServer = false;

		Client client = new Client(address, port, Constants.CLIENT_PORT, this);
		networkInterface = client;
		
		gui.addText("Connected!.\n");
	}
	
	public void update() {
		turn = !turn;
		if(checkForVictory()){
			gui.addText("The game has been won!!");
			turn = false;
		}
		gui.repaint();
	}

	/**
	 * Checks if a player has won the game
	 */
	private boolean checkForVictory(){
		
		//check rows
		for(int row = 0; row < board.length; row++) {
			for(int col = 0; col < board[row].length; col++){
					if(checkFiveInACol(row, col, myMark) ||
					   checkFiveInARow(row, col, myMark) ||
					   checkFiveInCross(row, col, myMark) ||
					   checkFiveInCross2(row, col, myMark) ||
					   checkFiveInACol(row, col, otherMark) ||
					   checkFiveInARow(row, col, otherMark) ||
					   checkFiveInCross2(row, col, otherMark) ||
					   checkFiveInCross(row, col, otherMark))
							return true;
				}
			}
		
		return false;
	}
	
	private boolean checkFiveInARow(int row, int col, char mark) {
		if(col+4 >= Constants.BOARD_SIZE) return false;
		
		return(board[row][col].getCurrentMark() == mark &&
				   board[row][col+1].getCurrentMark() == mark &&
				   board[row][col+2].getCurrentMark() == mark &&
				   board[row][col+3].getCurrentMark() == mark &&
				   board[row][col+4].getCurrentMark() == mark);
	}
	private boolean checkFiveInACol(int row, int col, char mark) {
		if(row+4 >= Constants.BOARD_SIZE) return false;
		
		return(board[row][col].getCurrentMark() == mark &&
				   board[row+1][col].getCurrentMark() == mark &&
				   board[row+2][col].getCurrentMark() == mark &&
				   board[row+3][col].getCurrentMark() == mark &&
				   board[row+4][col].getCurrentMark() == mark);
	}
	
	private boolean checkFiveInCross(int row, int col, char mark) {
		if(row+4 >= Constants.BOARD_SIZE || col + 4 >= Constants.BOARD_SIZE) return false;
		
		return((board[row][col].getCurrentMark() == mark &&
				   board[row+1][col+1].getCurrentMark() == mark &&
				   board[row+2][col+2].getCurrentMark() == mark &&
				   board[row+3][col+3].getCurrentMark() == mark &&
				   board[row+4][col+4].getCurrentMark() == mark));
	}
	
	private boolean checkFiveInCross2(int row, int col, char mark) {
		if(row+4 >= Constants.BOARD_SIZE || col - 4 < 0) return false;
		
		return((board[row][col].getCurrentMark() == mark &&
				   board[row+1][col-1].getCurrentMark() == mark &&
				   board[row+2][col-2].getCurrentMark() == mark &&
				   board[row+3][col-3].getCurrentMark() == mark &&
				   board[row+4][col-4].getCurrentMark() == mark));
	}

	/**
	 * Starts up a GUI without an associated player, in order
	 * to check the appearance of the GUI.
	 */
	public static void main(String args[]) {
		Game game = new Game();
	}
}
